import numpy as np
import matplotlib.pyplot as plot
import pandas as pd

def crossover(p1,p2):
    weight=np.random.rand()
    return p1*weight+p2*(1-weight)


f=lambda x:x**2
fitness=lambda x:-x**2
fitness_sum=lambda x_array: np.sum(fitness(x) for x in x_array) / len(x_array)
fitness_prob=lambda x_array: np.exp([fitness(x) for x in x_array])/np.sum(np.exp([fitness(x) for x in x_array]))
mutate=lambda p:p+np.random.rand()*0.1
crossover_rate=0.8
mutate_rate=0.1
x=np.linspace(-2,2,1000)
y=f(x)
num=10
x_parent=np.random.uniform(-2, 2, num)
x_fitness=fitness_sum(x_parent)
iter_num=0
while iter_num<20:
    x_children=x_parent.copy()
    prob=fitness_prob(x_children)
    #杂交
    cross_num=int(crossover_rate * num)
    cross_index=np.random.choice(num, cross_num, replace=False)
    for i in cross_index:
        x_children[i]=crossover(x_children[i],x_children[int(np.random.choice(len(x_children),1,p=prob))])
    #变异
    mutate_num=int(mutate_rate*num)
    mutate_index=np.random.choice(num,mutate_num,replace=False)
    for i in mutate_index:
        x_children[i]=mutate(x_children[i])
    #合并父代与子代
    x_group=np.concatenate([x_children, x_parent])
    prob = fitness_prob(x_group)
    next_index=np.argsort(prob)[-num:]
    x_parent=x_group[next_index]
    pop_fit=fitness_sum(x_children)
    print("第{n}代种群的适应度：{x:.5f}".format(n=iter_num, x=pop_fit))
    iter_num=iter_num+1
    if abs(pop_fit)<0.00001:
        break
#plot.plot(x,y)
#plot.scatter(x_parent, y_parent, c='r')
#plot.show()